#include    "sendrtmp.h"

#define msleep(x) usleep(x*1000)

static char* TRAK_TYPE_NAME[] = {
        "AUDIO",
        "VIDEO"
};

static int fd = -1;

int 
appendflvhead(int fd)
{
    static const char HEAD[] = {0x46, 0x4C, 0x56, 0x01, 0x05, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00};
    static const char META[] = {
    0x12, 0x00, 0x01, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x02, 0x00, 0x0A, 0x6F, 0x6E, 0x4D, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x08, 0x00, 0x00, 
    0x00, 0x10, 0x00, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x00, 0x40, 0xA5, 0x18, 
    0xE9, 0xFB, 0xE7, 0x6C, 0x8B, 0x00, 0x05, 0x77, 0x69, 0x64, 0x74, 0x68, 0x00, 0x40, 0x7E, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x00, 0x40, 0x71, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x76, 0x69, 0x64, 0x65, 0x6F, 0x64, 0x61, 0x74, 
    0x61, 0x72, 0x61, 0x74, 0x65, 0x00, 0x40, 0x65, 0xF7, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 
    0x66, 0x72, 0x61, 0x6D, 0x65, 0x72, 0x61, 0x74, 0x65, 0x00, 0x40, 0x2E, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x0C, 0x76, 0x69, 0x64, 0x65, 0x6F, 0x63, 0x6F, 0x64, 0x65, 0x63, 0x69, 0x64, 
    0x00, 0x40, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x61, 0x75, 0x64, 0x69, 0x6F, 
    0x64, 0x61, 0x74, 0x61, 0x72, 0x61, 0x74, 0x65, 0x00, 0x40, 0x3D, 0x3E, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x0F, 0x61, 0x75, 0x64, 0x69, 0x6F, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x72, 0x61, 
    0x74, 0x65, 0x00, 0x40, 0xE5, 0x88, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x61, 0x75, 0x64, 
    0x69, 0x6F, 0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x73, 0x69, 0x7A, 0x65, 0x00, 0x40, 0x30, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x73, 0x74, 0x65, 0x72, 0x65, 0x6F, 0x01, 0x01, 0x00, 
    0x0C, 0x61, 0x75, 0x64, 0x69, 0x6F, 0x63, 0x6F, 0x64, 0x65, 0x63, 0x69, 0x64, 0x00, 0x40, 0x24, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0x6D, 0x61, 0x6A, 0x6F, 0x72, 0x5F, 0x62, 0x72, 
    0x61, 0x6E, 0x64, 0x02, 0x00, 0x04, 0x69, 0x73, 0x6F, 0x6D, 0x00, 0x0D, 0x6D, 0x69, 0x6E, 0x6F, 
    0x72, 0x5F, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x02, 0x00, 0x01, 0x31, 0x00, 0x11, 0x63, 
    0x6F, 0x6D, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6C, 0x65, 0x5F, 0x62, 0x72, 0x61, 0x6E, 0x64, 0x73, 
    0x02, 0x00, 0x04, 0x69, 0x73, 0x6F, 0x6D, 0x00, 0x07, 0x65, 0x6E, 0x63, 0x6F, 0x64, 0x65, 0x72, 
    0x02, 0x00, 0x0C, 0x4C, 0x61, 0x76, 0x66, 0x35, 0x35, 0x2E, 0x30, 0x2E, 0x31, 0x30, 0x30, 0x00, 
    0x08, 0x66, 0x69, 0x6C, 0x65, 0x73, 0x69, 0x7A, 0x65, 0x00, 0x41, 0x91, 0x8E, 0x3C, 0xA8, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x09, 
    0x00, 0x00, 0x01, 0x70
    };

    int ret = -1;
    if ((ret=write(fd, HEAD, sizeof(HEAD))) != sizeof(HEAD)){
        mp4u_log_error("appendflvhead error");
        return -1;
    }
    if ((ret=write(fd, META, sizeof(META))) != sizeof(META)){
        mp4u_log_error("appendflvhead error");
        return -1;
    }


    return ret;
}

int
appendflvtag(uint32_t type, char *data, unsigned int size, unsigned int traktimestamp)
{
    static char TAGHEAD[11] = {0};
    static char PREVTAGSIZE[4] = {0};
    int         ret = -1;
    uint32_t    len = 11 + size;
    char       *p = TAGHEAD, *ps = PREVTAGSIZE;
   
    if (fd <= 0){
        mp4u_log_error("appendflvtag fd not initialed!");
        return -1;
    }
    if (data == NULL || size < 3){
        return -1;
    }

    if (type == RTMP_PACKET_TYPE_AUDIO){
        p[0] = 0x08;
    }else if (type == RTMP_PACKET_TYPE_VIDEO){
        p[0] = 0x09;
    }else{
        return 0;
    }
  
    p[1] = (size >> 16) & 0xFF;
    p[2] = (size >> 8) & 0xFF;
    p[3] = size & 0xFF;
    p[4] = (traktimestamp>> 16) & 0xFF;
    p[5] = (traktimestamp>> 8) & 0xFF;
    p[6] = traktimestamp & 0xFF;

    if (traktimestamp > 16777215) {
        p[7] = (traktimestamp>> 24) & 0xFF;
    }else{
        p[7] = 0x00;
    }

    ps[0] = (len >> 24) & 0xFF;
    ps[1] = (len >> 16) & 0xFF;
    ps[2] = (len >> 8)  & 0xFF;
    ps[3] = len         & 0xFF;

    if ((ret=write(fd, p, 11)) != 11){
        mp4u_log_error("append flvtag error");
        return -1;
    }
    if ((ret=write(fd, data, size)) != size){
        mp4u_log_error("append flvtag error");
        return -2;
    }
    if ((ret=write(fd, ps, 4)) != 4){
        mp4u_log_error("append flvtag error");
        return -3;
    }

    return ret;
}

int 
sendpacket(RTMP *rtmp, unsigned int packettype, char *data, unsigned int size, unsigned int mtraktimestamp)
{
    int ret = -1;
    if (rtmp == NULL) return -1; 

    RTMPPacket packet;
    RTMPPacket_Reset(&packet);
    RTMPPacket_Alloc(&packet, size);
  
    packet.m_hasAbsTimestamp = 0;
    packet.m_packetType = packettype;
    packet.m_nChannel = 0x04;
    packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
    //packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
    packet.m_nTimeStamp = mtraktimestamp;
    packet.m_nInfoField2 = rtmp->m_stream_id;
    packet.m_nBodySize = size;
    memcpy(packet.m_body, data, size);
  
    ret = RTMP_SendPacket(rtmp, &packet, 0);
    mp4u_log("rmtp sendpacket packettype:%d ret:%d  size:%u", packettype, ret, size);
  
    RTMPPacket_Free(&packet);

    if (fd > 0)
        appendflvtag(packettype, data, size, mtraktimestamp);
  
    return ret;
} 

static const AVal av_setdataframe = AVC("@setDataFrame");

#define SAVC(x) static const AVal av_##x = AVC(#x)
SAVC(onMetaData);


const AMFObjectProperty copyright_prop = {AVC("copyright"), AMF_STRING, {.p_aval = AVC("firehood")}};
const AMFObjectProperty vcodecid_prop = {AVC("videocodecid"), AMF_NUMBER, {.p_number = FLV_CODECID_H264}};
const AMFObjectProperty acodecid_prop = {AVC("audiocodecid"), AMF_NUMBER, {.p_number = FLV_CODECID_AAC}};


int
sendmetadata(RTMP *rtmp, rtmpmetadata_t  *metadata)
{
    static char body[1024] = {0};
    int         ret = -1, len;
    AMFObject   amfobj = {};
    char       *p = body, *pend = body + sizeof(body);

    if (metadata == NULL) return -1;
      
    p = AMF_EncodeString(p, pend, &av_setdataframe);
    p = AMF_EncodeString(p, pend, &av_onMetaData);

    const AMFObjectProperty width_prop = { AVC("width"), AMF_NUMBER, {.p_number = metadata->width}};
    const AMFObjectProperty height_prop = { AVC("height"), AMF_NUMBER, {.p_number = metadata->height}};
    const AMFObjectProperty framerate_prop = { AVC("framerate"), AMF_NUMBER, {.p_number = metadata->framerate}};

    AMF_AddProp(&amfobj, &copyright_prop);
    AMF_AddProp(&amfobj, &width_prop);
    AMF_AddProp(&amfobj, &height_prop);
    AMF_AddProp(&amfobj, &framerate_prop);
    AMF_AddProp(&amfobj, &vcodecid_prop);
    AMF_AddProp(&amfobj, &acodecid_prop);
   
    p = AMF_Encode(&amfobj, p, pend);
  
    len = p - body;
    if ((ret = sendpacket(rtmp, RTMP_PACKET_TYPE_INFO, body, len, 0)) != 1){
        mp4u_log_error("sendpacket RTMP_PACKET_TYPE_INFO error:%d", ret);
        return ret;
    }

    int i = 0;
    body[i++] = 0x17; // 1:keyframe  7:AVC
    body[i++] = 0x00; // AVC sequence header  
    body[i++] = 0x00;  
    body[i++] = 0x00;  
    body[i++] = 0x00; // fill in 0;  

    memcpy(&body[i], metadata->spspps, metadata->spsppslen);
    i= i + metadata->spsppslen;
 
    mp4u_log("spsppslen :%d  i:%d",  metadata->spsppslen, i);
    if ((ret = sendpacket(rtmp, RTMP_PACKET_TYPE_VIDEO, body, i, 0)) != 1){
        mp4u_log_error("sendpacket RTMP_PACKET_TYPE_VIDEO spspps error:%d", ret);
        return ret;
    }

    i = 0;
    //body[i++] = 0xAF;
    body[i++] = (0x0A << 4) | (0x3 << 2) | ((metadata->audiosamplesize == 16?1:0) << 1) | (metadata->audiochannels == 2?1:0);
    body[i++] = 0x00;

    memcpy(&body[i], metadata->audiospeccfg, metadata->audiospeccfglen);
    i = i + metadata->audiospeccfglen;
   
    if ((ret = sendpacket(rtmp, RTMP_PACKET_TYPE_AUDIO, body, i, 0)) != 1){
        mp4u_log_error("sendpacket RTMP_PACKET_TYPE_AUDIO config error:%d", ret);
        return ret;
    }

    return ret;
}

u_char*
readnalu(naluunit_t *nalu, u_char *data)
{
    nalu->size = mp4u_mp4_get_32value(data);
    if (nalu->size == 0) return NULL;
    nalu->type = data[4] & 0x1F;
    nalu->data = &data[4];

    mp4u_log("readnalu size:%d type:%d data:%p",
              nalu->size, nalu->type, nalu->data);
    return data + 4 + nalu->size;
}

int
sendh264packet(RTMP *rtmp, char *data, unsigned int size, int keyframe, unsigned int mtraktimestamp)
{
    int ret = -1;
    if (data == NULL && size < 11){
        return -1;
    }
  
    char *body = (char*)malloc(size+9);
    if (body == NULL){
        mp4u_log_error("sendh264packet malloc error size:%d", size);
        return -1;
    }
  
    mp4u_log("keyframe:%d", keyframe);
    int i = 0;  
    if (keyframe){
        body[i++] = 0x17;// 1:Iframe  7:AVC
    }else{  
        body[i++] = 0x27;// 2:Pframe  7:AVC  
    }

    body[i++] = 0x01;// AVC NALU  
    body[i++] = 0x00;  
    body[i++] = 0x00;  
    body[i++] = 0x00;  
  
    // NALU data  
    memcpy(&body[i], data, size);
  
    if ((ret = sendpacket(rtmp, RTMP_PACKET_TYPE_VIDEO, body, i+size, mtraktimestamp)) != 1){
        mp4u_log_error("sendpacket h264package error:%d", ret);
        return ret;
    }

    free(body); 

    return ret;
}

int
sendaacpacket(RTMP *rtmp, char *data, unsigned int size, unsigned int traktimestamp)
{
    int ret = -1;
    if (data == NULL || size < 3){
        return -1;
    }
  
    char *body = (char*)malloc(size+2);
    if (body == NULL){
        mp4u_log_error("sendaacpacket malloc error size:%d", size);
        return -1;
    }
  
    int i = 0;
    body[i++] = 0xAF;
    body[i++] = 0x01;

    // raw audio data 
    memcpy(&body[i], data, size);
  
    if ((ret = sendpacket(rtmp, RTMP_PACKET_TYPE_AUDIO, body, i+size, traktimestamp)) != 1){
        mp4u_log_error("sendpacket aacpackage error:%d", ret);
        return ret;
    }

    free(body); 
    return ret;
}


int
sendmp4file(RTMP *rtmp, const char *file)
{
    static char                 data[1024*100] = {0};
    int                         ret = -1;
    u_char                     *pkeyframe = NULL;
    mp4u_mp4_stts_entry_t      *ts_entry = NULL;
    mp4u_mp4_stsc_entry_t      *sc_entry = NULL;
    off_t                       chunkoffset[2], frameoffset;
    uint32_t                    trakidx, frameid, framesize, chunkbegin, chunkframes, escape, sleeptime, tscount, tsduration, finishedtrakcnt = 0, finished = 0, timestampstep =0;
    uint32_t                    trakframeidx[2], trakchunkidx[2], trakchunkentryidx[2], tsentryidx[2], tsentrycnt[2], chunkframecnt[2], traktimestamp[2];
    mp4u_file_t                 mp4;
    mp4u_trak_t                *trak;
    mp4u_mp4_avc1_atom_t       *avc1_atom;
    mp4u_mp4_mp4a_atom_t       *mp4a_atom;
    rtmpmetadata_t              metadata;
    long                        start, now;
    struct timeval              timev;


    if ((ret=mp4u_init(&mp4, file))!= MP4U_OK){
        mp4u_log_error("mp4u_init error:%d", ret);
        return ret; 
    }
   
    ret = mp4u_process(&mp4);
    mp4u_log("process result:%d", ret);

    trak = mp4.trak.elts;
    for (trakidx=0; trakidx<mp4.trak.nelts; trakidx++){
        if (trak[trakidx].avcC_size > 0){
            pkeyframe = trak[trakidx].stss_data_buf.pos;
            metadata.spspps = (char*)trak[trakidx].avcC_data_buf.pos;
            metadata.spsppslen  = trak[trakidx].avcC_data_buf.last - trak[trakidx].avcC_data_buf.pos;

            avc1_atom = (mp4u_mp4_avc1_atom_t*)trak[trakidx].avc1_atom_buf.pos;
            metadata.width = mp4u_mp4_get_16value(avc1_atom->framepixel);
            metadata.height = mp4u_mp4_get_16value(avc1_atom->framepixel + 2);
            metadata.framerate = 15;

            mp4u_log("avcC_size:%d spspps:%p spsppslen:%d width:%d height:%d %.2x|%.2x|%.2x|%.2x", 
                     trak[trakidx].avcC_size, metadata.spspps, metadata.spsppslen,
                     metadata.width, metadata.height, avc1_atom->framepixel[0], 
                     avc1_atom->framepixel[1], avc1_atom->framepixel[2], avc1_atom->framepixel[3]);

        }else{
            mp4a_atom = (mp4u_mp4_mp4a_atom_t*)trak[trakidx].mp4a_atom_buf.pos;
            metadata.audiochannels = mp4u_mp4_get_16value(mp4a_atom->channels);
            metadata.audiosamplesize = mp4u_mp4_get_16value(mp4a_atom->samplesize);
            metadata.audiosamplerate = mp4u_mp4_get_16value(mp4a_atom->samplerate);
 
            metadata.audiospeccfglen = trak[trakidx].esds_data_buf.pos[25];
            metadata.audiospeccfg = (char*)trak[trakidx].esds_data_buf.pos + 26;

            mp4u_log("esds  channels:%d samplesize:%d samplerate:%d audiospeccfglen:%d audiospeccfg[0]:%.2x|%.2x", 
                      metadata.audiochannels, metadata.audiosamplesize, metadata.audiosamplerate, metadata.audiospeccfglen,
                      metadata.audiospeccfg[0], metadata.audiospeccfg[1]);
        }
    }

    if (pkeyframe == NULL){
        mp4u_log_error("the video isn`t h264 encoded.");
        return MP4U_ERROR;
    }
     
    sendmetadata(rtmp, &metadata);

    uint32_t  curtimestamp, othertimestamp;
    gettimeofday(&timev, NULL);
    start = 1000*timev.tv_sec + timev.tv_usec/1000; //ms
    do{
        trak = mp4.trak.elts;
        for (trakidx=0; trakidx<mp4.trak.nelts; trakidx++){
            curtimestamp = traktimestamp[trakidx];
            othertimestamp = traktimestamp[mp4.trak.nelts - trakidx - 1];
            if (curtimestamp > othertimestamp){
                continue; 
            }

            gettimeofday(&timev, NULL);
            now = 1000*timev.tv_sec + timev.tv_usec/1000; //ms
            escape = now - start;
            mp4u_log("escape %d preframets:%d", escape, traktimestamp[trakidx]);
            while(escape < traktimestamp[trakidx]){
                sleeptime = (traktimestamp[trakidx]-escape);
                msleep(sleeptime);
                //msleep(500);
                escape += sleeptime;
                mp4u_log("sleeptime:%d escape:%d", sleeptime, escape);
            }

            frameid = trakframeidx[trakidx];
            if (frameid >= trak[trakidx].sample_sizes_entries){
                finishedtrakcnt++;
                if (finishedtrakcnt == mp4.trak.nelts)
                    finished = 1;        
                continue;
            }

            // get framesize
            if (trak[trakidx].stsz_data_buf.pos == NULL){
                framesize = mp4u_mp4_get_32value(trak[trakidx].stsz_atom_buf.pos + 12);
            }else{
                framesize = mp4u_mp4_get_32value(trak[trakidx].stsz_data_buf.pos + (sizeof(uint32_t) * frameid));
            }

            // get frameoffset
            if (mp4u_mp4_stco_is64(&trak[trakidx])){
                chunkbegin = mp4u_mp4_get_64value(trak[trakidx].co64_data_buf.pos + trakchunkidx[trakidx] * sizeof(uint64_t));
            }else{
                chunkbegin = mp4u_mp4_get_32value(trak[trakidx].stco_data_buf.pos + trakchunkidx[trakidx] * sizeof(uint32_t));
            }
            frameoffset = chunkbegin + chunkoffset[trakidx];
            

            sc_entry = (mp4u_mp4_stsc_entry_t*)(trak[trakidx].stsc_data_buf.pos + (sizeof(mp4u_mp4_stsc_entry_t)*trakchunkentryidx[trakidx]));
            chunkframes = mp4u_mp4_get_32value(sc_entry->samples);

            mp4u_log("%s trak[%d] chunk:%d frameid:%d traktimestamp:%d timescale:%d frameoffset:%lld framesize:%d ",
                      TRAK_TYPE_NAME[mp4u_mp4_is_video_trak(&trak[trakidx])], trakidx, trakchunkidx[trakidx], frameid, traktimestamp[trakidx],
                      trak[trakidx].timescale, (long long)frameoffset, framesize);
    
            mp4.mdat_data_buf.file_pos = frameoffset;
            if (mp4u_mp4_is_video_trak(&trak[trakidx])) {
                mp4u_read_file(mp4.mdat_data_buf.file, (u_char*)data, framesize, mp4.mdat_data_buf.file_pos);
                mp4u_log("frameid:%d mp4u_mp4_get_32value(pkeyframe):%d",frameid+1, mp4u_mp4_get_32value(pkeyframe)); 
                if ((frameid+1) == mp4u_mp4_get_32value(pkeyframe)) {
                    pkeyframe += sizeof(uint32_t);
                    sendh264packet(rtmp, data, framesize, 1, traktimestamp[trakidx]);
                }else{
                    sendh264packet(rtmp, data, framesize, 0, traktimestamp[trakidx]);
                }
            }else{
                mp4u_read_file(mp4.mdat_data_buf.file, (u_char*)data, framesize, mp4.mdat_data_buf.file_pos);
                sendaacpacket(rtmp, data, framesize, traktimestamp[trakidx]);
                //if (traktimestamp[trakidx] > 0)
                    //timestampstep++;
            }

            // get traktimestamp
            ts_entry = (mp4u_mp4_stts_entry_t*)(trak[trakidx].stts_data_buf.pos + (sizeof(mp4u_mp4_stts_entry_t)*tsentryidx[trakidx]));
            tscount = mp4u_mp4_get_32value(ts_entry->count);
            tsduration = ((double)mp4u_mp4_get_32value(ts_entry->duration) / (double)trak[trakidx].timescale) * 1000;
            traktimestamp[trakidx] += tsduration;
            traktimestamp[trakidx] += timestampstep;

            trakframeidx[trakidx]++;
            chunkframecnt[trakidx]++;
            tsentrycnt[trakidx]++;
            if (tsentryidx[trakidx] < (trak[trakidx].time_to_sample_entries - 1)){
                if (tsentrycnt[trakidx] == tscount) {
                    tsentryidx[trakidx]++;
                    tsentrycnt[trakidx] = 0;
                }
            }
            chunkoffset[trakidx] += framesize;
            if (trakchunkidx[trakidx] < trak[trakidx].chunks ){
                mp4u_log("chunkframecnt:%d   samples::%d start chunkid:%d", chunkframecnt[trakidx] , chunkframes, mp4u_mp4_get_32value(sc_entry->chunk));
                if (chunkframecnt[trakidx] == chunkframes){
                    trakchunkidx[trakidx]++;
                    chunkoffset[trakidx] = 0;
                    chunkframecnt[trakidx] = 0;
                    mp4u_log("trakchunkentryidx:%d  trakchunkidx:%d %d", trakchunkentryidx[trakidx] , trakchunkidx[trakidx], mp4u_mp4_get_32value(sc_entry->chunk));
                    if (trakchunkentryidx[trakidx] < trak[trakidx].sample_to_chunk_entries) {
                        //sc_entry = sc_entry + sizeof(mp4u_mp4_stsc_entry_t); //next sc_entry
                        sc_entry = (mp4u_mp4_stsc_entry_t*)(trak[trakidx].stsc_data_buf.pos + (sizeof(mp4u_mp4_stsc_entry_t)*(trakchunkentryidx[trakidx]+1)));
                        mp4u_log("trakchunkentryidx:%d  trakchunkidx:%d %d", trakchunkentryidx[trakidx] , trakchunkidx[trakidx], mp4u_mp4_get_32value(sc_entry->chunk));
                        if ((trakchunkidx[trakidx]+1) == mp4u_mp4_get_32value(sc_entry->chunk)){
                            trakchunkentryidx[trakidx]++; 
                        }
                    }
                }
            }
        }
    }while(!finished);

    mp4u_free(&mp4);
    return ret;  
}

int 
main(int argc, char *const *argv)
{
    int ret = 0;
    RTMP_LogSetLevel(RTMP_LOGDEBUG);
    RTMP *rtmp = RTMP_Alloc();
    RTMP_Init(rtmp);

    if((ret = RTMP_SetupURL(rtmp, (char*)argv[2])) < 0 ){
       mp4u_log_error("RTMP_SetupURL ret:%d error:%s", ret, strerror(errno));
       return -1;
    }

    RTMP_EnableWrite(rtmp);
    if((ret = RTMP_Connect(rtmp, NULL)) < 0 ){
       mp4u_log_error("RTMP_Connect ret:%d error:%s", ret, strerror(errno));
       return -1;
    }

    if((ret = RTMP_ConnectStream(rtmp,0)) < 0 ){
       mp4u_log_error("RTMP_ConnectStream ret:%d error:%s", ret, strerror(errno));
       return -1;
    }


    /*fd = open("/tmp/test.flv", O_RDWR|O_CREAT|O_APPEND, 0666);
    if (fd <= 0){
        mp4u_log("init flv file error");
        return 0;
    }
    if ((ret=appendflvhead(fd)) < 0){
        return 0;
    }*/

    sendmp4file(rtmp, argv[1]);

    if(rtmp){
       RTMP_Close(rtmp);
       RTMP_Free(rtmp);  
       rtmp = NULL;  
    }

    return ret;
}
